package com.srmt.common.retry;

import com.lark.oapi.core.exception.ClientTimeoutException;
import com.lark.oapi.core.exception.ServerTimeoutException;
import com.srmt.feishu.client.exception.FeishuApiException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.function.Predicate;

/**
 * 统一的重试处理器
 * 实现指数退避算法，用于处理429等可重试的错误
 * 
 * @author SRMT Development Team
 * @since 1.0.0
 */
public class RetryHandler {
    
    private static final Logger logger = LoggerFactory.getLogger(RetryHandler.class);
    
    private final RetryConfig config;
    private final Random random;
    
    /**
     * 构造函数
     * 
     * @param config 重试配置
     */
    public RetryHandler(RetryConfig config) {
        if (config == null) {
            throw new IllegalArgumentException("重试配置对象不能为null");
        }
        this.config = config;
        this.random = new Random();
    }
    
    /**
     * 执行可重试的操作
     * 
     * @param <T> 返回值类型
     * @param operation 要执行的操作
     * @param retryCondition 判断是否需要重试的条件
     * @param operationName 操作名称（用于日志）
     * @return 操作的返回值
     * @throws Exception 如果所有重试都失败
     */
    public <T> T executeWithRetry(
            Callable<T> operation,
            Predicate<Exception> retryCondition,
            String operationName) throws Exception {
        
        if (!config.isEnabled()) {
            logger.debug("[重试] 重试已禁用,直接执行操作: {}", operationName);
            return operation.call();
        }
        logger.debug("[重试] 重试已启用,开始执行操作: {}", operationName);
        int maxAttempts = config.getMaxAttempts();
        Exception lastException = null;
        
        for (int attempt = 0; attempt < maxAttempts; attempt++) {
            try {
                if (attempt > 0) {
                    long delay = calculateDelay(attempt);
                    logger.info("[重试] 操作 {} 的第 {}/{} 次尝试,延迟 {}ms",
                               operationName, attempt + 1, maxAttempts, delay);
                    Thread.sleep(delay);
                }
                
                T result = operation.call();
                
                if (attempt > 0) {
                    logger.info("[重试] 操作 {} 在 {} 次尝试后成功",
                               operationName, attempt + 1);
                }
                
                return result;
                
            } catch (Exception e) {
                lastException = e;
                
                // 检查是否应该重试
                if (!retryCondition.test(e)) {
                    logger.debug("[重试] 异常不可重试,立即抛出: {} - {}",
                                operationName, e.getMessage());
                    throw e;
                }
                
                // 检查是否还有重试机会
                if (attempt >= maxAttempts - 1) {
                    logger.error("[重试] 操作 {} 的所有 {} 次尝试已用尽",
                                operationName, maxAttempts);
                    throw e;
                }
                
                logger.warn("[重试] 操作 {} 的第 {}/{} 次尝试失败 - {}",
                           operationName, attempt + 1, maxAttempts, e.getMessage());
            }
        }
        
        // 不应该到达这里，但为了编译器满意
        throw lastException != null ? lastException :
              new IllegalStateException("重试处理器出现异常状态");
    }
    
    /**
     * 计算重试延迟（指数退避算法）
     * 
     * @param attempt 当前重试次数（从0开始）
     * @return 延迟时间（毫秒）
     */
    private long calculateDelay(int attempt) {
        // 基础延迟：initialDelay * (backoffFactor ^ attempt)
        long baseDelay = (long) (config.getInitialDelayMs() * 
                                 Math.pow(config.getBackoffFactor(), attempt - 1));
        
        // 限制最大延迟
        long delay = Math.min(baseDelay, config.getMaxDelayMs());
        
        // 添加随机抖动（如果启用）
        if (config.isJitterEnabled() && delay > 0) {
            // 添加 0-20% 的随机抖动
            int jitter = random.nextInt((int) (delay * 0.2));
            delay = delay + jitter;
            logger.debug("[重试] 计算的延迟: 基础={},抖动={}", baseDelay, delay);
        }
        
        return delay;
    }
    
    /**
     * 检查异常是否为429错误（速率限制）
     *
     * <p>检查策略：</p>
     * <ol>
     *   <li>直接检查是否是 {@link FeishuApiException} 并调用 {@link FeishuApiException#isRateLimitError()}</li>
     *   <li>遍历异常原因链，查找 {@link FeishuApiException}</li>
     *   <li>降级到字符串匹配（向后兼容旧代码）</li>
     * </ol>
     *
     * @param e 异常
     * @return 如果是429错误返回true
     */
    public static boolean isRateLimitException(Exception e) {
        if (e == null) {
            return false;
        }

        // 策略1: 直接检查是否是 FeishuApiException
        if (e instanceof FeishuApiException) {
            boolean isRateLimit = ((FeishuApiException) e).isRateLimitError();
            logger.debug("[重试] 检测到FeishuApiException, isRateLimitError={}, code={}",
                    isRateLimit, ((FeishuApiException) e).getCode());
            return isRateLimit;
        }

        // 网络异常导致也需要重试
        if (e instanceof ClientTimeoutException || e instanceof ServerTimeoutException) {
            logger.debug("[重试] 检测到ClientTimeoutException");
            return true;
        }

        // 策略2: 检查异常原因链中是否有 FeishuApiException
        Throwable cause = e.getCause();
        while (cause != null) {
            if (cause instanceof FeishuApiException) {
                boolean isRateLimit = ((FeishuApiException) cause).isRateLimitError();
                logger.debug("[重试] 在异常链中检测到FeishuApiException, isRateLimitError={}, code={}",
                    isRateLimit, ((FeishuApiException) cause).getCode());
                return isRateLimit;
            }
            cause = cause.getCause();
        }

        // 策略3: 降级到字符串匹配（向后兼容）
        String message = e.getMessage();
        if (message == null) {
            return false;
        }

        // 检查消息中是否包含429或rate limit相关的关键词
        String lowerMessage = message.toLowerCase();
        boolean isRateLimit = lowerMessage.contains("429") ||
                lowerMessage.contains("the result returned by the server is illegal");

        if (isRateLimit) {
            logger.warn("[重试] 通过字符串匹配检测到速率限制异常: {}", message);
        }

        return isRateLimit;
    }
    
    /**
     * 创建默认的429重试条件
     * 
     * @return 重试条件断言
     */
    public static Predicate<Exception> defaultRetryCondition() {
        return RetryHandler::isRateLimitException;
    }
    
    /**
     * 获取配置
     * 
     * @return 重试配置
     */
    public RetryConfig getConfig() {
        return config;
    }
}